package com.nq.service.impl;

/**

 * 开发者----股牛网络

 * 联系TG：gncms

 */
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.nq.common.ServerResponse;
import com.nq.common.SystemVersionEnum;
import com.nq.common.Valid;
import com.nq.common.calculator.UserFundsCalculator;
import com.nq.dao.*;
import com.nq.dao.fund.StFundKlineMapper;
import com.nq.dao.fund.StFundMapper;
import com.nq.dao.fund.StFundServiceChargeDetailsMapper;
import com.nq.dao.fund.StFundServiceChargeMapper;
import com.nq.dao.stock.StCommissionLevelMapper;
import com.nq.dao.stock.StUserLevelMapper;
import com.nq.fund.entity.StFund;
import com.nq.fund.entity.StFundKline;
import com.nq.fund.entity.StFundServiceCharge;
import com.nq.fund.entity.StFundServiceChargeDetails;
import com.nq.pojo.*;
import com.nq.pojo.vo.FundPositionRecordVo;
import com.nq.pojo.vo.StFundApplyDetailVo;
import com.nq.pojo.vo.StFundServiceChargeVo;
import com.nq.service.*;
import com.nq.stock.entity.StCommissionLevel;
import com.nq.stock.entity.StUserLevel;
import com.nq.utils.DateTimeUtil;
import com.nq.utils.DateUtils;
import com.nq.utils.KeyUtils;
import com.nq.utils.SymmetricCryptoUtil;
import com.nq.utils.email.SendHTMLMail;
import com.nq.vo.page.StockPageInfo;
import com.nq.vo.position.UserPositionVO;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

/**
 * 新股申购
 * @author lr
 * @date 2020/07/24
 */
@Service("StFundApplyService")
@Slf4j
public class StFundApplyServiceImpl implements StFundApplyService {



    @Value("${spring.profiles.active}")
    private String active;

    @Resource
    private StFundMapper stFundMapper;
    @Resource
    private StFundKlineMapper fundKlineMapper;
    @Resource
    private StFundApplyMapper stFundApplyMapper;
    @Resource
    private StFundApplyDetailMapper stFundApplyDetailMapper;
    @Resource
    private UserCashDetailMapper userCashDetailMapper;
    @Resource
    private ISiteProductService iSiteProductService;
    @Resource
    private IUserService iUserService;
    @Resource
    private StFundServiceChargeMapper fundServiceChargeMapper;
    @Resource
    private StFundServiceChargeDetailsMapper fundServiceChargeDetailsMapper;
    @Resource
    private IStUserLevelService stUserLevelService;
    @Resource
    private StUserLevelMapper stUserLevelMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private FundsApplyMapper fundsApplyMapper;

    @Resource
    private StCommissionLevelMapper commissionLevelMapper;

    @Resource
    private SendHTMLMail sendHTMLMail;


    @Override
    @Transactional
    public ServerResponse addUserFund(Integer fundId, String purchaseAmount, String payPwd, HttpServletRequest request) {

        /*实名认证开关开启*/
        SiteProduct siteProduct = iSiteProductService.getProductSetting();
        User user = this.iUserService.getCurrentRefreshUser(request);
        if (siteProduct.getRealNameDisplay() && (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()))) {
            return ServerResponse.createByErrorMsg("If the order fails, please authenticate with your real name first.");
        }

        // 校验支付密码
        String userPayPwd = user.getPayPwd();
        if (StringUtils.isBlank(userPayPwd)) {
            return ServerResponse.createByErrorMsg("You have not set a payment password yet. Please set a payment password before making a purchase!");
        }

        // 校验密码是否正确
        if (!SymmetricCryptoUtil.encryptPassword(payPwd).equals(userPayPwd)) {
            boolean isLocked = iUserService.isLocked(User.FUND_PAY_PWD_PREFIX, user.getId());
            if (isLocked) {
                return ServerResponse.createByErrorMsg("Purchase failed, The password has exceeded 5 times. Please wait for half an hour before making a purchase.");
            }
            return ServerResponse.createByErrorMsg("Purchase failed, The password you entered is incorrect, please re-enter it!");
        }

        // 查询基金是否存在
        if (null == fundId) {
            return ServerResponse.createByErrorMsg("Parameter error [fundId] is empty");
        }
        if (StringUtils.isBlank(purchaseAmount)) {
            return ServerResponse.createByErrorMsg("Parameter error [purchaseAmount] is empty");
        }

        // 需要更新当前价格， 取当天K线
        StFundKline kline = fundKlineMapper.queryCurrentKlineData(fundId);
        if (null == kline) {
            return ServerResponse.createByErrorMsg("K-line data for the day does not exist");
        }

        StFund updateFund = new StFund();
        updateFund.setId(fundId);
        updateFund.setCurrentPrice(kline.getClose());
        stFundMapper.updateById(updateFund);


        StFund fund = stFundMapper.selectById(fundId);
        if (null == fund) {
            return ServerResponse.createByErrorMsg("The fund does not exist.");
        }

        // 判断是否可以购买
        Integer fundLevel = fund.getUserLevel();

        // 查询用户交易金额  买入基金金额
        Integer userId = user.getId();
        Integer userLevel = stUserLevelService.getUserLevelByUserId(userId);
        if (userLevel < fundLevel) {
            StUserLevel fundLevels = stUserLevelMapper.selectById(fundLevel);
            StUserLevel userLevels = stUserLevelMapper.selectById(userLevel);
            return ServerResponse.createByErrorMsg("Your current rating is:" + userLevels.getName () + ". You can not purchase the fund. You need a rating of " + fundLevels.getName () + " to purchase the fund");
        }

        // 判断最小购买金额
        Integer minBuyMoment = fund.getMinBuyMoment();
        if (minBuyMoment > Integer.parseInt(purchaseAmount)) {
            return ServerResponse.createByErrorMsg("The minimum amount currently purchased by the fund is:" + minBuyMoment);
        }

        // 判断该用户购买本基金的次数是否超过本基金设置的最大购买次数
        QueryWrapper<StFundApply> applyQueryWrapper = new QueryWrapper<>();
        applyQueryWrapper.eq("fund_id", fundId);
        applyQueryWrapper.eq("user_id", userId);
        Long buyTimes = stFundApplyMapper.selectCount(applyQueryWrapper);

        Integer maxBuyTimes = fund.getMaxBuyTimes();
        if (buyTimes > maxBuyTimes) {
            return ServerResponse.createByErrorMsg("The number of times you have purchased this fund has exceeded the maximum number of purchases. The maximum number of purchases of this fund is:" + maxBuyTimes);
        }



        boolean isTrad = false;
        // 查询用户的配置账户是否有余额
        BigDecimal tradingAmount = user.getTradingAmount();

        if (tradingAmount.compareTo(BigDecimal.ZERO) > 0) {
            isTrad = true;
        }

        boolean isEnable = false;
        // 可用余额
        BigDecimal enableAmt = user.getEnableAmt();
        if (enableAmt.compareTo(BigDecimal.ZERO) > 0) {
            isEnable = true;
        }
        BigDecimal frontEndLoad = BigDecimal.ZERO;
        BigDecimal backEndLoad = BigDecimal.ZERO;
        BigDecimal managementFee = BigDecimal.ZERO;
        BigDecimal twelveFee = BigDecimal.ZERO;
        // 基金购买金额
        BigDecimal buyAmount = new BigDecimal(purchaseAmount);
        // 查询购买时需要执行的手续费 买入时执行Front-EndLoad  ManagementFee  12b-1 Fee
        // 记录总的购买手续费
        BigDecimal totalServiceCharge = new BigDecimal(BigInteger.ZERO);

        // 计算总的手续费
        List<StFundServiceCharge> chargeList = fundServiceChargeMapper.queryBuyFeeByFundId(fundId);
        for (StFundServiceCharge charge : chargeList) {
            // 费率
            BigDecimal proportion = charge.getProportion();
            // 单挑/多条
            Integer single = charge.getSingle();
            // 买入时才执行
            Integer type = charge.getType();
            if (StFundServiceCharge.BUY.equals(type)) {
                // 如果是单条手续费规则 直接计算即可
                if (StFundServiceCharge.SINGLE_YES.equals(single)) {
                    if (charge.getName().contains("Front")) {
                        frontEndLoad = charge.getProportion();
                    } else if (charge.getName().contains("12b-1")) {
                        twelveFee = charge.getProportion();
                    }
                    BigDecimal fee = buyAmount.multiply(proportion).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                    totalServiceCharge = totalServiceCharge.add(fee);
                }else {
                    // 需要查询详情
                    Integer chargeId = charge.getId();
                    List<StFundServiceChargeDetails> details = fundServiceChargeDetailsMapper.queryByChargeId(chargeId);

                    for (StFundServiceChargeDetails chargeDetails : details) {
                        Integer beginNum = chargeDetails.getBeginNum();
                        Integer endNum = chargeDetails.getEndNum();
                        // 判断购买金额处于哪个区间
                        if (buyAmount.compareTo(new BigDecimal(beginNum)) >= 0 && buyAmount.compareTo(new BigDecimal(endNum)) <=0){
                            BigDecimal prop = chargeDetails.getProportion();
                            BigDecimal fee = buyAmount.multiply(prop).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                            totalServiceCharge = totalServiceCharge.add(fee);
                            if (charge.getName().contains("Management")) {
                                managementFee = chargeDetails.getProportion();
                            }
                        }

                    }
                }
            }

        }

        // 更新账户余额 手续费加购买金额
        synchronized (user.getId()) {
            boolean isSuccess = updateUserAccount(user, buyAmount.add(totalServiceCharge));
            if (!isSuccess) {
                throw new IllegalArgumentException("Purchase failed, account balance is insufficient");
            }
        }
        // 当日净值
        BigDecimal currentPrice = fund.getCurrentPrice();
        // 份额 = 购买价格 除以 当日净值
        BigDecimal purchaseShare = buyAmount.divide(currentPrice, 6, BigDecimal.ROUND_HALF_UP);

        // 生产订单号
        String orderNumber = KeyUtils.getUniqueKey();

        // 增加购买详情
        StFundApplyDetail stFundApplyDetail = new StFundApplyDetail();
        stFundApplyDetail.setPurchaseAmount(buyAmount);
        stFundApplyDetail.setInitPrice(currentPrice);
        stFundApplyDetail.setFundId(fundId);
        stFundApplyDetail.setUserId(user.getId());
        stFundApplyDetail.setPurchaseShare(purchaseShare);
        stFundApplyDetail.setStatus(Valid.VALID_0);
        stFundApplyDetail.setTradeType(Valid.VALID_0);
        stFundApplyDetail.setAddTime(new Date());
        stFundApplyDetail.setBeginTime(DateUtil.offsetDay(new Date(), 1));
        stFundApplyDetail.setOrderNumber(orderNumber);
        stFundApplyDetail.setFrontEndLoad(frontEndLoad);
        stFundApplyDetail.setManagementFee(managementFee);
        stFundApplyDetail.setTwelveFee(twelveFee);
        stFundApplyDetail.setBackEndLoad(backEndLoad);
        stFundApplyDetailMapper.insert(stFundApplyDetail);

        // 新增购买记录
        StFundApply newFundApply = new StFundApply();
        newFundApply.setFundId(fundId);
        newFundApply.setOrderNumber(orderNumber);
        newFundApply.setUserId(user.getId());
        newFundApply.setAddTime(new Date());
        newFundApply.setStatus(Valid.VALID_S0);
        newFundApply.setPurchaseShare(purchaseShare);
        newFundApply.setPurchaseAmount(buyAmount);
        newFundApply.setInitPrice(currentPrice);
        newFundApply.setBeginTime(new Date());
        stFundApplyMapper.insert(newFundApply);

        // 记录资金详情
        UserCashDetail ucd = new UserCashDetail();
        ucd.setAgentId(user.getAgentId());
        ucd.setAgentName(user.getAgentName());
        ucd.setUserId(user.getId());
        ucd.setUserName(user.getRealName());
        ucd.setDeType("Buy fund");
        ucd.setDeSummary("Amount of purchase: " + buyAmount +", Service charge: " + totalServiceCharge);
        ucd.setDeAmt(buyAmount.add(totalServiceCharge).negate());
        ucd.setAddTime(new Date());
        ucd.setIsRead(Integer.valueOf(0));
        userCashDetailMapper.insert(ucd);

        // 发送邮箱
        if(SystemVersionEnum.global.name().equals(active)) {
            sendHTMLMail.sendFundEmail(user, stFundApplyDetail);
        }


        return ServerResponse.createBySuccess("Successful purchase");
    }

    @Override
    @Transactional
    public ServerResponse sellUserFund(String orderNumber, String purchaseAmount, String payPwd, HttpServletRequest request) {
        /*实名认证开关开启*/
        SiteProduct siteProduct = iSiteProductService.getProductSetting();
        User user = this.iUserService.getCurrentRefreshUser(request);
        if (siteProduct.getRealNameDisplay() && (StringUtils.isBlank(user.getRealName()) || StringUtils.isBlank(user.getIdCard()))) {
            return ServerResponse.createByErrorMsg("The redemption failed, please authenticate with your real name first.");
        }

        if (StringUtils.isBlank(orderNumber)) {
            return ServerResponse.createByErrorMsg("Parameter error [orderNumber] is empty");
        }

        if (StringUtils.isBlank(purchaseAmount)) {
            return ServerResponse.createByErrorMsg("Parameter error [purchaseAmount] is empty");
        }

        QueryWrapper<StFundApply> applyQueryWrapper = new QueryWrapper<>();
        applyQueryWrapper.eq("order_number", orderNumber);
        StFundApply stFundApply = stFundApplyMapper.selectOne(applyQueryWrapper);
        if (null == stFundApply) {
            return ServerResponse.createByErrorMsg("The fund is not held.");
        }

        // 判断赎回金额是否大于持有金额
        if (new BigDecimal(purchaseAmount).compareTo(stFundApply.getPurchaseAmount().setScale(2, RoundingMode.HALF_UP)) > 0) {
            return ServerResponse.createByErrorMsg("The redemption amount cannot be greater than the holding amount.");
        }

        // 根据基金ID查询基金是否存在
        Integer fundId = stFundApply.getFundId();

        // 需要更新当前价格， 取当天K线
        StFundKline kline = fundKlineMapper.queryCurrentKlineData(fundId);
        if (null == kline) {
            return ServerResponse.createByErrorMsg("K-line data for the day does not exist");
        }

        StFund updateFund = new StFund();
        updateFund.setId(fundId);
        updateFund.setCurrentPrice(kline.getClose());
        stFundMapper.updateById(updateFund);

        StFund fund = stFundMapper.selectById(fundId);
        if (null == fund) {
            return ServerResponse.createByErrorMsg("The fund does not exist.");
        }

        // 校验支付密码
        String userPayPwd = user.getPayPwd();
        if (StringUtils.isBlank(userPayPwd)) {
            return ServerResponse.createByErrorMsg("You have not set a payment password yet. Please set a payment password before making a purchase!");
        }

        // 校验密码是否正确
        if (!SymmetricCryptoUtil.encryptPassword(payPwd).equals(userPayPwd)) {
            boolean isLocked = iUserService.isLocked(User.FUND_PAY_PWD_PREFIX, user.getId());
            if (isLocked) {
                return ServerResponse.createByErrorMsg("Purchase failed, The password has exceeded 5 times. Please wait for half an hour before making a purchase.");
            }
            return ServerResponse.createByErrorMsg("Purchase failed, The password you entered is incorrect, please re-enter it!");
        }

        BigDecimal holdPurchaseShare = stFundApply.getPurchaseShare();
        // 判断持有份额是否大于0
        if (holdPurchaseShare.compareTo(BigDecimal.ZERO) <= 0) {
            return ServerResponse.createByErrorMsg("The amount of the fund is: " + holdPurchaseShare + "，It cannot exceed this value.");
        }

        // 卖出金额
        BigDecimal sellAmount = new BigDecimal(purchaseAmount);

        // 将卖出的金额转成份额 卖出的金额 / 本基金当前净值
        // 当前基金的价格
        BigDecimal currentPrice = fund.getCurrentPrice();
        // 卖出的份额
        BigDecimal sellPurchaseShare = sellAmount.divide(currentPrice, 6, RoundingMode.HALF_DOWN);

        // 剩余份额
        BigDecimal surplusPurchaseShare = holdPurchaseShare.subtract(sellPurchaseShare).setScale(6, BigDecimal.ROUND_HALF_DOWN);

        // 判断是否全部卖出
        BigDecimal hold = holdPurchaseShare.setScale(2, BigDecimal.ROUND_HALF_DOWN);
        BigDecimal sell = sellPurchaseShare.setScale(2, BigDecimal.ROUND_HALF_DOWN);
        BigDecimal surplus = sell.subtract(hold);
        if (surplus.compareTo(BigDecimal.ZERO) == 0) {
            stFundApply.setStatus(StFundApply.STATUS_FULL_REDEMPTION);
        }else {
            stFundApply.setStatus(StFundApply.STATUS_PARTIAL_REDEMPTION);
        }

        stFundApply.setPurchaseShare(surplusPurchaseShare);
        // 当前持有的金额 = 剩余份额 乘以 当前净值
        BigDecimal newHoldAmount = surplusPurchaseShare.multiply(currentPrice).setScale(6, BigDecimal.ROUND_HALF_DOWN);
        stFundApply.setPurchaseAmount(newHoldAmount);
        stFundApplyMapper.updateById(stFundApply);

        // 增加详情
        StFundApplyDetail stFundApplyDetail = new StFundApplyDetail();
        stFundApplyDetail.setPurchaseAmount(sellAmount);
        stFundApplyDetail.setFundId(fundId);
        stFundApplyDetail.setUserId(user.getId());
        stFundApplyDetail.setPurchaseShare(sellPurchaseShare);
        stFundApplyDetail.setStatus(Valid.VALID_0);
        stFundApplyDetail.setTradeType(Valid.VALID_1);
        stFundApplyDetail.setAddTime(new Date());
        stFundApplyDetail.setBeginTime(DateUtil.offsetDay(new Date(), 1));
        stFundApplyDetail.setOrderNumber(stFundApply.getOrderNumber());

        // 购买时的净值
        BigDecimal initPrice = stFundApply.getInitPrice();
        // 涨跌幅
        BigDecimal up = currentPrice.subtract(initPrice)
                .divide(initPrice, 6, RoundingMode.HALF_UP);
        stFundApplyDetail.setUp(up.multiply(BigDecimal.valueOf(100)));
        // 计算盈亏 应该是卖出价格减去买入价格得到每份额的涨跌，然后乘以卖出的份额
        BigDecimal profitAndLoss = currentPrice.subtract(initPrice).multiply(sellPurchaseShare).setScale(6, BigDecimal.ROUND_HALF_UP);


        // 扣除卖出的手续费 -- 应该是卖出的份额*买入时的价格 就是本金
        BigDecimal sellServiceCharge = initPrice.multiply(sellPurchaseShare).setScale(6, BigDecimal.ROUND_HALF_UP);
        BigDecimal frontEndLoad = BigDecimal.ZERO;
        BigDecimal backEndLoad = BigDecimal.ZERO;
        BigDecimal managementFee = BigDecimal.ZERO;
        BigDecimal twelveFee = BigDecimal.ZERO;
        // 计算总的手续费
        BigDecimal totalServiceCharge = new BigDecimal(BigInteger.ZERO);
        List<StFundServiceCharge> chargeList = fundServiceChargeMapper.querySellFeeByFundId(fundId);
        for (StFundServiceCharge charge : chargeList) {
            Integer single = charge.getSingle();
            Integer type = charge.getType();
            if (StFundServiceCharge.SELL.equals(type)) {
                // 如果是单条手续费规则 直接计算即可
                if (StFundServiceCharge.SINGLE_YES.equals(single)) {
                    BigDecimal proportion = charge.getProportion();
                    BigDecimal fee = sellServiceCharge.multiply(proportion).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                    totalServiceCharge = totalServiceCharge.add(fee);
                }else {
                    // 需要查询详情
                    Integer chargeId = charge.getId();
                    List<StFundServiceChargeDetails> details = fundServiceChargeDetailsMapper.queryByChargeId(chargeId);

                    for (StFundServiceChargeDetails chargeDetails : details) {
                        Integer beginNum = chargeDetails.getBeginNum();
                        Integer endNum = chargeDetails.getEndNum();
                        // 判断持有时间处于哪个区间
                        Date addTime = stFundApply.getAddTime();
                        Date now = new Date();
                        long betweenDay = DateUtil.between(addTime, now, DateUnit.DAY);
                        if (betweenDay >= beginNum && betweenDay <= endNum) {
                            BigDecimal proportion = chargeDetails.getProportion();
                            BigDecimal fee = sellServiceCharge.multiply(proportion).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                            totalServiceCharge = totalServiceCharge.add(fee);
                            if (charge.getName().contains("Back-End")) {
                                backEndLoad = chargeDetails.getProportion();
                            }
                        }

                    }
                }
            }
        }


        // 卖出时，需要校验 本基金是否是封闭期类型，如果是 判断是否在封闭期内,需要收违约金
        Integer closed = fund.getClosed();
        if (StFund.CLOSED_YES.equals(closed)){
            // 判断购买时的日期是否在封闭期内
            Date addTime = stFundApply.getAddTime();
            DateTime aaBefore = new DateTime(addTime);

            Integer closedDay = fund.getClosedDay();
            // 计算出封闭期到期的日期
            Date currentTime = new Date();
            DateTime time = new DateTime(currentTime);

            DateTime dateTime = DateUtil.offsetDay(aaBefore, closedDay);
            if (time.before(dateTime)) {
                // 需要扣除违约金了
                BigDecimal defaultRates = fund.getDefaultRates();
                // 需要扣除的违约金
                BigDecimal defaultAmount = sellServiceCharge.multiply(defaultRates).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                boolean  isSuccess = updateUserAccount(user, defaultAmount);
                if (!isSuccess) {
                    throw new IllegalArgumentException("The available funds are insufficient to deduct the penalty!");
                }

                // 记录资金详情
                UserCashDetail ucd = new UserCashDetail();
                ucd.setAgentId(user.getAgentId());
                ucd.setAgentName(user.getAgentName());
                ucd.setUserId(user.getId());
                ucd.setUserName(user.getRealName());
                ucd.setDeType("Liquidated damages");
                ucd.setDeSummary("addTime: " + aaBefore + ", dateTime: " + dateTime + ", now: " + time);
                // 扣除的金额是负数
                ucd.setDeAmt(defaultAmount.negate());
                ucd.setAddTime(new Date());
                ucd.setIsRead(Integer.valueOf(0));
                userCashDetailMapper.insert(ucd);
            }

        }



        boolean  isSuccess = updateUserAccount(user, totalServiceCharge);
        if (!isSuccess) {
            throw new IllegalArgumentException("There is not enough money available to deduct the handling fee!");
        }

        // 记录卖出基金手续费
        UserCashDetail chargeCash = new UserCashDetail();
        chargeCash.setAgentId(user.getAgentId());
        chargeCash.setAgentName(user.getAgentName());
        chargeCash.setUserId(user.getId());
        chargeCash.setUserName(user.getRealName());
        chargeCash.setDeType("Sell fund service charge");
        // 扣除的金额是负数
        chargeCash.setDeAmt(totalServiceCharge.negate());
        chargeCash.setAddTime(new Date());
        chargeCash.setIsRead(Integer.valueOf(0));
        userCashDetailMapper.insert(chargeCash);

        // 给上级返佣金, 是用户盈利的金额
        returnsTheCommission(user, profitAndLoss);

        // 卖出的钱退还到账户在定时中, 需要在卖出的第二天才能到账
        stFundApplyDetail.setProfitAndLoss(profitAndLoss);
        stFundApplyDetail.setInitPrice(currentPrice);
        stFundApplyDetail.setFrontEndLoad(frontEndLoad);
        stFundApplyDetail.setManagementFee(managementFee);
        stFundApplyDetail.setTwelveFee(twelveFee);
        stFundApplyDetail.setBackEndLoad(backEndLoad);
        stFundApplyDetailMapper.insert(stFundApplyDetail);
        
        // 发送邮箱
        if(SystemVersionEnum.global.name().equals(active)) {
            sendHTMLMail.sendFundEmail(user, stFundApplyDetail);
        }

        return ServerResponse.createBySuccessMsg("The funds will arrive the next day");
    }


    public static void main(String[] args) {
        Date addTime = DateUtil.parse("2024-08-30 09:19:50");
        Integer closedDay = 3;
        // 计算出封闭期到期的日期
        DateTime dateTime = DateUtil.offsetDay(addTime, closedDay);
        System.out.println(dateTime);
        DateTime aa = DateUtil.parse("2024-09-03 02:12:28");
        if (aa.before(dateTime)) {
            System.out.println(DateTime.now());
            System.out.println("未到封闭期");
        }
        System.out.println(DateTime.now());
    }

    /**
     * 给上级返佣金
     */
    private void returnsTheCommission(User user, BigDecimal reckonEnable){
        // 获取等级及佣金比例


        // 查询用户上级,上上级,上上上级
        Integer parentId = user.getParentId();
        if (null != parentId) {
            User next1 = userMapper.getParentUser(parentId);
            if (null != next1) {
                // 取当前用户的等级
                StUserLevel userLevel = queryUserLevel(next1.getId());

                if (null != userLevel.getFirstFee() && userLevel.getFirstFee().compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal firstFee = userLevel.getFirstFee();
                    BigDecimal commission = reckonEnable.multiply(firstFee);
                    // 返佣
                    BigDecimal enableAmt = next1.getEnableAmt();
                    enableAmt = enableAmt.add(commission);
                    next1.setEnableAmt(enableAmt);
                    // 获取的佣金金额
                    BigDecimal userIndexAmt = next1.getUserIndexAmt();
                    userIndexAmt = userIndexAmt.add(commission);
                    next1.setUserIndexAmt(userIndexAmt);
                    userMapper.updateByPrimaryKeySelective(next1);

                    cashDetail(next1, commission, "Commission", "The user level of the rebated party is: " + userLevel.getName() + ", FeeType: FirstFeeType, Proportion: " + userLevel.getFirstFee());
                }

                // 继续上一级
                Integer parentId1 = next1.getParentId();
                if (null != parentId1) {
                    User next2 = userMapper.getParentUser(parentId1);
                    if (null != next2) {
                        StUserLevel userLevel1 = queryUserLevel(next2.getId());

                        if (null != userLevel1.getSecondFee() && userLevel1.getSecondFee().compareTo(BigDecimal.ZERO) > 0) {
                            BigDecimal secondFee = userLevel1.getSecondFee();
                            BigDecimal commission = reckonEnable.multiply(secondFee);
                            // 返佣
                            BigDecimal enableAmt = next2.getEnableAmt();
                            enableAmt = enableAmt.add(commission);
                            next2.setEnableAmt(enableAmt);
                            // 获取的佣金金额
                            BigDecimal userIndexAmt = next2.getUserIndexAmt();
                            userIndexAmt = userIndexAmt.add(commission);
                            next2.setUserIndexAmt(userIndexAmt);
                            userMapper.updateByPrimaryKeySelective(next2);

                            cashDetail(next2, commission, "Commission", "The user level of the rebated party is: " + userLevel1.getName() + ", FeeType: SecondFee, Proportion: " + userLevel1.getSecondFee());
                        }

                        // 继续上一级
                        Integer parentId2 = next2.getParentId();
                        if (null != parentId2) {
                            User next3 = userMapper.getParentUser(parentId2);
                            if (null != next3) {
                                StUserLevel userLevel2 = queryUserLevel(next3.getId());

                                if (null != userLevel2.getThirdFee() && userLevel2.getThirdFee().compareTo(BigDecimal.ZERO) > 0) {
                                    BigDecimal thirdFee = userLevel2.getThirdFee();
                                    BigDecimal commission = reckonEnable.multiply(thirdFee);
                                    // 返佣
                                    BigDecimal enableAmt = next3.getEnableAmt();
                                    enableAmt = enableAmt.add(commission);
                                    next3.setEnableAmt(enableAmt);
                                    // 获取的佣金金额
                                    BigDecimal userIndexAmt = next3.getUserIndexAmt();
                                    userIndexAmt = userIndexAmt.add(commission);
                                    next3.setUserIndexAmt(userIndexAmt);
                                    userMapper.updateByPrimaryKeySelective(next3);

                                    cashDetail(next3, commission, "Commission", "The user level of the rebated party is: " + userLevel2.getName() + ", FeeType: ThirdFee, Proportion: " + userLevel2.getThirdFee());
                                }

                            }
                        }

                    }


                }

            }


        }

    }

    protected StUserLevel queryUserLevel(Integer userId){
        // 获取用户等级
        Integer userLevel = stUserLevelService.getUserLevelByUserId(userId);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("level", userLevel);
        List<StUserLevel> list = stUserLevelMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        // 获取配置
        StUserLevel userLevelInfo = list.get(0);
        return userLevelInfo;
    }

    private void cashDetail(User user, BigDecimal money, String deType, String deSum){
        // 记录卖出基金手续费
        UserCashDetail chargeCash = new UserCashDetail();
        chargeCash.setAgentId(user.getAgentId());
        chargeCash.setAgentName(user.getAgentName());
        chargeCash.setUserId(user.getId());
        chargeCash.setUserName(user.getRealName());
        chargeCash.setDeType(deType);
        chargeCash.setDeSummary(deSum);
        chargeCash.setDeAmt(money);
        chargeCash.setAddTime(new Date());
        chargeCash.setIsRead(Integer.valueOf(0));
        userCashDetailMapper.insert(chargeCash);
    }

    // 卖出股票的钱退回对应账户的逻辑
    private int returnCorrespondAccount(User user, BigDecimal reckonEnable){
        // 查询用户配资记录 总的配资金额
        Integer userId = user.getId();
        Integer amount = fundsApplyMapper.getUserTotalAmountOfFunds(userId);
        if (null == amount) {
            // 配资账户未激活 直接退还到可用资金
            BigDecimal enableAmt = user.getEnableAmt();
            enableAmt = enableAmt.add(reckonEnable);

            User updateUser = new User();
            updateUser.setId(userId);
            updateUser.setEnableAmt(enableAmt);
            return userMapper.updateByPrimaryKeySelective(updateUser);
        }

        // 用户总的配资金额
        BigDecimal fundsAmount = new BigDecimal(amount);
        // 用户目前持有的配资金额  不包含保证金
        BigDecimal tradingAmount = user.getTradingAmount();
        BigDecimal enableAmt = user.getEnableAmt();

        // 需要退还到配资账户的钱
        BigDecimal fundsReturn = fundsAmount.subtract(tradingAmount);
        // 如果卖出股票的钱大于已使用的配资的钱，就先退还配资的钱，然后将剩余的退还到可用资金
        if (reckonEnable.compareTo(fundsReturn) > 0) {
            tradingAmount = tradingAmount.add(fundsReturn);

            // 卖出的钱如果有剩余需要退还到可用金额
            BigDecimal available = reckonEnable.subtract(fundsReturn);
            if (available.compareTo(BigDecimal.ZERO) > 0) {
                enableAmt = enableAmt.add(available);
            }
        }else {
            tradingAmount = tradingAmount.add(reckonEnable);
        }

        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setTradingAmount(tradingAmount);
        updateUser.setEnableAmt(enableAmt);
        return userMapper.updateByPrimaryKeySelective(updateUser);
    }

    @Override
    public ServerResponse fundTransactionRecords(Integer pageNum, Integer pageSize, HttpServletRequest request) {

        User user = this.iUserService.getCurrentRefreshUser(request);
        if (null == user) {
            return ServerResponse.createByErrorMsg("Please log in and check.");
        }

        Page<Object> page = PageHelper.startPage(pageNum, pageSize);
        Integer userId = user.getId();
        List<StFundApplyDetailVo> stFundApplyDetails = stFundApplyDetailMapper.queryFundApplyDetails(userId);
        for (StFundApplyDetailVo vo : stFundApplyDetails) {
            Integer tradeType = vo.getTradeType();
            if (StFundApplyDetail.STATUS_SELL.equals(tradeType)) {
                // 卖出时需要计算盈亏和百分比

                // 总订单的盈亏
                BigDecimal profitAndLoss = vo.getProfitAndLoss();
                vo.setChange(profitAndLoss);

            }

        }

        PageInfo pageInfo = new PageInfo(page);
        pageInfo.setList(stFundApplyDetails);
        return ServerResponse.createBySuccess(pageInfo);
    }

    @Override
    public ServerResponse fundPositionRecord(Integer pageNum, Integer pageSize, HttpServletRequest request) {
        User user = this.iUserService.getCurrentRefreshUser(request);
        if (null == user) {
            return ServerResponse.createByErrorMsg("Please log in and check.");
        }

        List<FundPositionRecordVo> fundPositionRecordVos = Lists.newArrayList();

        List<FundPositionRecordVo> list = stFundApplyMapper.fundPositionRecord(user.getId());
        //计算总收益
        BigDecimal totalProfit = new BigDecimal(BigInteger.ZERO);
        for (FundPositionRecordVo vo : list) {

            // 盈亏应该是当前基金的净值 减去 购买时的净值 乘以当前持有的份额
            BigDecimal currentPrice = vo.getCurrentPrice();
            BigDecimal initPrice = vo.getInitPrice();

            BigDecimal purchaseShare = vo.getPurchaseShare();
            BigDecimal profit = currentPrice.subtract(initPrice).multiply(purchaseShare).setScale(2, BigDecimal.ROUND_HALF_DOWN);
            vo.setProfit(profit);

            if(null != profit) {
                totalProfit = totalProfit.add(profit);
            }

            // 持有金额应该时当前净值 乘以 持有份额
            BigDecimal holdPrice = currentPrice.multiply(purchaseShare).setScale(2, BigDecimal.ROUND_HALF_DOWN);
            vo.setHoldPrice(holdPrice);
            fundPositionRecordVos.add(vo);
        }

        PageInfo pageInfo = new PageInfo(fundPositionRecordVos);
        StockPageInfo stockPageInfo = new StockPageInfo(fundPositionRecordVos);
        BeanUtils.copyProperties(pageInfo, stockPageInfo);
        stockPageInfo.setAllProfitAndLose(totalProfit.setScale(2, BigDecimal.ROUND_HALF_DOWN));
        return ServerResponse.createBySuccess(stockPageInfo);
    }

    @Override
    public ServerResponse holdFundPurchaseShare(String orderNumber, HttpServletRequest request) {
        User user = this.iUserService.getCurrentRefreshUser(request);
        if (null == user) {
            return ServerResponse.createByErrorMsg("Please log in and check.");
        }

        FundPositionRecordVo apply = stFundApplyMapper.holdFundPurchaseShare(orderNumber);
        if (null == apply) {
            return ServerResponse.createByErrorMsg("Fund records don't exist.");
        }
        BigDecimal currentPrice = apply.getCurrentPrice();
        BigDecimal purchaseShare = apply.getPurchaseShare();
        // 计算基金持有的天数
        long days = DateUtils.daysBetween(apply.getAddTime(), new Date());
        apply.setDays(days);
        // 计算持有金额
        BigDecimal holdPrice = currentPrice.multiply(purchaseShare);
        apply.setHoldPrice(holdPrice);
        return ServerResponse.createBySuccess(apply);
    }

    @Override
    public ServerResponse queryFundServiceCharge(Integer fundId, HttpServletRequest request) {

        // 查询基金配置的手续费
        List<StFundServiceCharge> list = fundServiceChargeMapper.queryFundServiceChargeByFundId(fundId);

        ArrayList<StFundServiceChargeVo> serviceChargeVos = new ArrayList<>();

        for (StFundServiceCharge charge : list) {
            StFundServiceChargeVo serviceChargeVo = new StFundServiceChargeVo();
            BeanUtils.copyProperties(charge, serviceChargeVo);

            // 判断是否是一对多
            Integer single = charge.getSingle();
            if(StFundServiceCharge.SINGLE_NO.equals(single)){
                // 查询详情
                Integer chargeId = charge.getId();
                String name = charge.getName();

                List<StFundServiceChargeDetails> stFundServiceChargeDetails = fundServiceChargeDetailsMapper.queryByChargeId(chargeId);
                if (name.indexOf(StFundServiceCharge.BACK_END_LOAD) != -1){
                    serviceChargeVo.setDetails(stFundServiceChargeDetails);
                }

                if (name.indexOf(StFundServiceCharge.MANAGEMENT_FEE) != -1){
                    serviceChargeVo.setDetails(stFundServiceChargeDetails);
                }

            }
            serviceChargeVos.add(serviceChargeVo);
        }

        return ServerResponse.createBySuccess(serviceChargeVos);
    }

    @Override
    public ServerResponse queryFundServiceChargeDetails(Integer chargeId, HttpServletRequest request) {
        List<StFundServiceChargeDetails> stFundServiceChargeDetails = fundServiceChargeDetailsMapper.queryByChargeId(chargeId);
        return ServerResponse.createBySuccess(stFundServiceChargeDetails);
    }

    /**
     * 修改股票购买扣款路径  先扣配资账户(不包括保证金) 不够了 再扣可用资金
     * @param user
     * @param buyAmount
     * @return
     */
    public boolean updateUserAccount(User user, BigDecimal buyAmount) {

        // 判断配资是否大于支付金额  配资金额首先要减去冻结金额(配资保证金 + 挂单金额)
        BigDecimal tradingAmount = user.getTradingAmount();

        // 配资账户中扣除购买金额
        tradingAmount = tradingAmount.subtract(buyAmount);

        if (tradingAmount.compareTo(BigDecimal.ZERO) == 0) {
            // 扣除配置的钱后 配资账户为0 再去扣除用户余额的钱 没有报错
            iUserService.updateTradingAmount(user.getId(),  new BigDecimal("0"), null);
            return true;
        }

        if (tradingAmount.compareTo(BigDecimal.ZERO) < 0) {
            // 扣除配资的钱后 配资账户为0 再去扣除用户余额的钱 没有报错
            BigDecimal enableAmt = user.getEnableAmt();
            // 这里使用加法  是因为配资的钱已经是负数了
            enableAmt = enableAmt.add(tradingAmount);

            // 如果扣完配置的钱 还不够 继续扣余额的钱  也还不够  那么就报错
            if (enableAmt.compareTo(BigDecimal.ZERO) < 0) {
                return false;
            }

            iUserService.updateTradingAmount(user.getId(),  new BigDecimal("0"), enableAmt);
            return true;
        }

        iUserService.updateTradingAmount(user.getId(),  tradingAmount, null);
        return true;
    }
}